1.問卷鑲嵌介面的設計構想
2.程式實作
3.Dart語言學習: @override注釋
4.介面成果

Score_Page.dart(1)將問卷的七個題目,和每個題目的選項,以上下滑動視窗顯示在介面上。
(2)針對每題的回答,使用Map(Dictionary)的Key和Value,將每題使用者勾選的選項儲存在變數中,讓程式進行總分計算,並按照總分級距,回傳對應的疾病嚴重程度到App介面。
針對以上,在該Dart檔案,程式架構如下圖:
(1)class Question{} 將問卷的七個題目,和每個題目的選項,以上下滑動視窗顯示在介面上
自定義 Dart 類別,代表一個問題的數據結構
// 定義了一個 Dart 類別 Question,用於封裝表示問題的數據
// 包含每個問題的內容(問題內容、選項和鍵值),然後在ScorePageState中創建了一個questions列表,其中包含所有的問題
// 這種設計可以方便地將問題的相關數據組織起來,將多個 Question 對象組成一個問題集合,用於測驗或問卷等應用場景
class Question {
  final String question;  // `final`代表不可變的屬性,代表問題的文字描述
  final List<String> options;  // 代表問題的選項列表,選項以字符串的形式存儲在列表中
  final String key;  // 代表問題的唯一鍵值,將用於識別和查找特定的問題
  // 是該類別的構造函式,接收問題、選項和鍵值作為必要的參數
  // 通過這個構造函式,可以創建一個 Question 對象,並初始化其中的屬性
  Question({required this.question, required this.options, required this.key});
}
(2)Widget buildQuestion(): 用於建立單一個問題的 UI
這段程式碼是用於建立單個問題的 UI 的方法,並處理用戶的選擇。以下是對它的詳細說明:
buildQuestion 方法是一個小部件,接受以下參數:
question:問題的文字描述。options:問題的選項列表。onOptionSelected:當用戶選擇選項時的回調函式。currentQuestion:當前問題的唯一鍵值,用於識別問題。Column 小部件用於垂直排列問題文本和選項。
問題文本使用 Text 小部件顯示,並設置字體樣式。
使用 options.map 方法將每個選項映射為 ListTile 小部件。
ListTile 包括問題選項的文本 (Text) 和選項的 Radio 按鈕。Radio 按鈕用於表示選項,value 是選項的分數,groupValue 是該問題的當前選擇分數。onChanged 回調函式會被觸發,將選擇的分數更新到 scores 映射中,並調用 onOptionSelected 回調函式。這個方法的主要作用是顯示單個問題,讓用戶選擇選項,並根據用戶的選擇更新 scores 映射,這個映射將用於計算症狀總分。這種設計允許用戶回答多個問題,並在 UI 上即時反映他們的選擇。
// buildQuestion() 方法用於構建單一個問題的 UI,包括問題文本和選項列表,用戶可以通過點擊選項來選擇分數
  Widget buildQuestion(String question, List<String> options, Function(int) onOptionSelected, String currentQuestion) {  // 選項都列出來,讓使用者點選
    return Column(
      children: [
        Text(question, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
        ...options.map((option) {
          int optionScore = options.indexOf(option);  // 第一個選項為0分, 若 options.indexOf(option) + 1: 第一個選項為1分
          return ListTile(
            title: Text(option),  // 顯示選項文字
            leading: Radio(
              value: optionScore,  // 選項的分數值
              groupValue: scores[currentQuestion],   // 當前問題的用戶選擇分數
              onChanged: (int? value) {
                if (value != null) {
                  setState(() {
                    scores[currentQuestion] = value;   // 更新問題的用戶選擇分數
                  });
                  onOptionSelected(value);   // 調用回調函式以處理選擇
                }
              },
            ),
          );
        }).toList(),
      ],
    );
  }
(3)Widget build(): 用於構建整個分數頁面的 UI,包括: 問題列表、症狀總分顯示、儲存按鈕和查看分數歷史圖表build 方法中,它是整個分數頁面的 UI 構建部分,處理以下主要內容:
主題和外觀設定
Theme 小部件設置應用程式的主題風格,包括主要顏色和 AppBar 的背景色。Scaffold 和 AppBar**
Scaffold 小部件構建整個頁面的基本結構,包括背景色。AppBar,顯示應用程式的標題為 "國際攝護腺症狀評分表: IPSS"。問題列表
ListView.builder 構建問題列表,其中每個問題都是通過 buildQuestion 方法構建的。questions 列表,並根據索引動態生成問題 UI。症狀總分顯示
Row 小部件,將症狀總分和症狀嚴重程度顯示在界面上。scores 映射中的值計算,然後顯示在界面上。與之前提到的 buildQuestion 方法不同,這部分程式碼是分數頁面的整體結構,包括整個界面的佈局、主題風格和按鈕處理。這個 build 方法是 Flutter 小部件生命週期中的一部分,當小部件需要構建其 UI 時會被調用。
@override
// build() 方法用於構建整個分數頁面的 UI,包括: 問題列表、症狀總分顯示、儲存按鈕和查看分數歷史圖表按鈕
// '評分頁面', 症狀總分, 儲存, 查看分數歷史圖表
Widget build(BuildContext context) {
return Theme(
  data: ThemeData(
    // primaryColor: const Color(0xFFC2185B),  // 使用自定義顏色作為主要顏色
      primarySwatch: Colors.pink,  // 主題色彩
      appBarTheme: const AppBarTheme(backgroundColor: Color(0xFFC2185B))  // 使用自定義顏色作為 AppBar 的背景色
  ),
  child: Scaffold(
    backgroundColor: backgroundColor,  // 背景色
    appBar: AppBar(title: const Text('國際攝護腺症狀評分表: IPSS')),
    body: Column(  // 將問題由上到下垂直排列
      children: [
        Expanded(
          // 使用 ListView.builder 構建問題列表,每個問題都是通過 buildQuestion() 方法構建的
          child: ListView.builder(
            itemCount: questions.length,
            itemBuilder: (context, index) {
              var question = questions[index];
              return buildQuestion(
                question.question, // 問題文本
                question.options, // 選項列表
                // 使用 setState 方法來處理問題的選擇,同時更新症狀總分和背景顏色
                (int score) => setState(() => scores[question.key] = score),
                question.key,
              );
            },
          ),
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: Text(
                // 顯示症狀總分
                '症狀總分: ${scores.values.reduce((a, b) => a + b)}',
                style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: Text(
                // 顯示症狀嚴重程度
                '症狀嚴重程度: ${scores.values.reduce((a, b) => a + b) <= 7 ? '輕度' : (scores.values.reduce((a, b) => a + b) <= 19 ? '中度' : '重度')}',
                style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
            ),
          ],
        ),
      ],
    ),
  ),
);
}
@override注釋(1)@override注釋
@override
Widget build(BuildContext context){}
@override:這是 Dart 語言提供的一個注釋,用來表示接下來的方法將覆蓋(重寫)父類別中具有相同名稱的方法。這個注釋通常用在子類別中,當你想要重寫父類別中已經存在的方法時。
在上述代碼中,@override 注釋用在 build 方法上,這是一個常見的做法,因為 build 方法是 Flutter 中的一個核心方法,用於構建小部件的 UI。
Widget build(BuildContext context):這是一個方法的定義,它在 State 子類別中覆蓋了父類別 StatefulWidget 的 build 方法。在 Flutter 中,build 方法是用於構建小部件的 UI 表示的地方。
BuildContext context:這是 build 方法的參數,它提供了上下文信息,允許小部件訪問 Flutter 應用程式的環境和配置。它是一個重要的參數,通常需要在構建 UI 時使用。總結,@override 注釋告訴編譯器,這個方法將覆蓋父類別的方法,並且該方法用於構建小部件的 UI。當 Flutter 需要重新渲染小部件時,它將調用這個方法來生成新的 UI 表示。

你所有的努力,不該是為了讓他人佩服,而是讓自己真心以自己為傲
All your efforts should be aimed not at earning admiration from others, but at genuinely making yourself proud.
今天享受了一杯熱可可,工作進度報告也順利~晚上吃了美味又健康的晚餐,平淡的充實的一天,早早睡去明天繼續!